package com.hsbc.dev.teamo4.sms.sm.service.impl;

import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.Lists;
import com.google.common.collect.Multimap;
import com.hsbc.dev.teamo4.sms.common.utils.data.LevelUtil;
import com.hsbc.dev.teamo4.sms.sm.dao.IPermissionDao;
import com.hsbc.dev.teamo4.sms.sm.dao.impl.PermissionDaoImpl;
import com.hsbc.dev.teamo4.sms.sm.dto.DepartmentDto;
import com.hsbc.dev.teamo4.sms.sm.dto.MenuDto;
import com.hsbc.dev.teamo4.sms.sm.dto.PermissionDto;
import com.hsbc.dev.teamo4.sms.sm.po.Department;
import com.hsbc.dev.teamo4.sms.sm.po.Menu;
import com.hsbc.dev.teamo4.sms.sm.po.Permission;
import com.hsbc.dev.teamo4.sms.sm.service.IDepartmentService;
import com.hsbc.dev.teamo4.sms.sm.service.IMenuService;
import com.hsbc.dev.teamo4.sms.sm.service.IPermissionDistributeService;
import org.springframework.util.CollectionUtils;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @author:Kevin
 * @version:
 * @Project: permission_manage
 * @Package: com.hsbc.dev.teamo4.sms.sm.service.impl
 * @Description:
 * @Date date: 2018/7/28
 */
public class TreeServiceImpl {
    private IDepartmentService iDepartmentService=new DepartmentServiceImpl();
    private IMenuService iMenuService=new MenuServiceImpl();
    private IPermissionDistributeService iPermissionDistributeService= new PermissionDistributeImpl();

    private IPermissionDao iPermissionDao=new PermissionDaoImpl();
    /**
     * get departmentTree
     * @return departmentTree
     */
    public List<DepartmentDto> departmentTree(){
        List<Department> departments=iDepartmentService.queryEntityList();

        List<DepartmentDto> departmentDtoList=Lists.newArrayList();
        for (Department department:departments){
            DepartmentDto departmentDto=DepartmentDto.adapt(department);
            departmentDtoList.add(departmentDto);
        }
        return departmentListToTree(departmentDtoList);
    }

    /**
     * departmentListToTree
     * @param departmentDtoList
     * @return List<DepartmentDto>
     */
    private List<DepartmentDto> departmentListToTree(List<DepartmentDto> departmentDtoList){
        if(CollectionUtils.isEmpty(departmentDtoList)){
            return Lists.newArrayList();
        }
        Multimap<String,DepartmentDto> departmentDtoMultimap= ArrayListMultimap.create();
        List<DepartmentDto> rootList=Lists.newArrayList();
        for (DepartmentDto departmentDto:departmentDtoList){
            departmentDtoMultimap.put(departmentDto.getDepartmentLevel(),departmentDto);
            if(LevelUtil.ROOT.equals(departmentDto.getDepartmentLevel())){
                rootList.add(departmentDto);
            }
        }

        Collections.sort(rootList, new Comparator<DepartmentDto>() {
            @Override
            public int compare(DepartmentDto o1, DepartmentDto o2) {
                return o1.getDepartmentOrder()-o2.getDepartmentOrder();
            }
        });
        //Recursive Traversal Tree
        transformDepartmentTree(departmentDtoList,LevelUtil.ROOT,departmentDtoMultimap);
        return rootList;
    }

    /**
     * transformDepartmentTree
     * @param departmentDtoList
     * @param level
     * @param departmentDtoMultimap
     */
    private void transformDepartmentTree(List<DepartmentDto> departmentDtoList, String level, Multimap<String, DepartmentDto> departmentDtoMultimap){
        for (DepartmentDto departmentDto : departmentDtoList) {
            String nextLevel = LevelUtil.calculateLevel(level, departmentDto.getDepartmentOrder());
            List<DepartmentDto> tempDepartmentDtoList = (List<DepartmentDto>) departmentDtoMultimap.get(nextLevel);
            if (CollectionUtils.isEmpty(tempDepartmentDtoList)) {
                //sort
                Collections.sort(tempDepartmentDtoList, departmentDtoComparator);
                //next department
                departmentDto.setDepartmentDtoList(tempDepartmentDtoList);
                //deal with next level
                transformDepartmentTree(tempDepartmentDtoList, nextLevel, departmentDtoMultimap);
            }
        }
    }

    /**
     * roleTree
     * @param roleId
     * @param userId
     * @return List<MenuDto>
     */
    public List<MenuDto> roleTree(String roleId,String userId){
        //获取当前用户已经分配的权限
        List<Permission>  userPermissionList=iPermissionDistributeService.getCurrentUserPermissionList(userId);
       //获取当前角色分配的权限
        List<Permission> rolePermissionList=iPermissionDistributeService.getRolePermissionList(roleId);

        Set<String> userPermissionIdSet=userPermissionList.stream().map(Permission::getId).collect(Collectors.toSet());
        Set<String> rolePermissionIdSet=rolePermissionList.stream().map(Permission::getId).collect(Collectors.toSet());

        List<Permission> allPermissionList=iPermissionDao.queryAllEntity();
        Set<Permission> permissionSet=new HashSet<>(allPermissionList);
        permissionSet.addAll(userPermissionList);
        List<PermissionDto> permissionDtoList=Lists.newArrayList();
        for(Permission permission:permissionSet){
            PermissionDto permissionDto=PermissionDto.adapt(permission);
            if(userPermissionIdSet.contains(permission.getId())){
                permissionDto.setHasPermission(true);
            }
            if(rolePermissionIdSet.contains(permission.getId())){
                permissionDto.setChecked(true);
            }
            permissionDtoList.add(permissionDto);
        }
        return permissionTotree(permissionDtoList);
    }

    /**
     * permissionTotree
     * @param permissionDtoList
     * @return List<MenuDto>
     */
    public List<MenuDto> permissionTotree(List<PermissionDto> permissionDtoList){
         if(CollectionUtils.isEmpty(permissionDtoList)){
             return Lists.newArrayList();
         }
         List<MenuDto> menuDtoList=menuTree();

         Multimap<String,PermissionDto> menuIdPermissionMap=ArrayListMultimap.create();
         for (PermissionDto permissionDto:permissionDtoList){
             if(permissionDto.getIsEnable()){
                 menuIdPermissionMap.put(permissionDto.getMenuId(),permissionDto);
             }
         }
        bindPermissionWithOrder(menuDtoList,menuIdPermissionMap);
        return menuDtoList;
    }

    /**
     * bindPermissionWithOrder
     * @param menuDtoList
     * @param menuIdPermissionMap
     */
    private void bindPermissionWithOrder(List<MenuDto> menuDtoList,Multimap<String,PermissionDto> menuIdPermissionMap){
        if(CollectionUtils.isEmpty(menuDtoList)){
            return;
        }
        for (MenuDto menuDto:menuDtoList){
            List<PermissionDto> permissionDtoList= (List<PermissionDto>) menuIdPermissionMap.get(menuDto.getId());
            if(CollectionUtils.isEmpty(permissionDtoList)){
                Collections.sort(permissionDtoList,permissionDtoComparator);
                menuDto.setPermissionDtoList(permissionDtoList);
            }
            bindPermissionWithOrder(menuDto.getMenuDtoList(),menuIdPermissionMap);
        }
    }

    /**
     * menuTree
     * @return
     */
    public List<MenuDto> menuTree(){
        List<Menu> menuList=iMenuService.queryEntityList();

        List<MenuDto> menuDtoList=Lists.newArrayList();
        for (Menu menu:menuList){
            MenuDto menuDto=MenuDto.adapt(menu);
            menuDtoList.add(menuDto);
        }
        return menuListToTree(menuDtoList);
    }

    /**
     * menuListToTree
     * @param menuDtoList
     * @return
     */
    private List<MenuDto> menuListToTree(List<MenuDto> menuDtoList){
        if(CollectionUtils.isEmpty(menuDtoList)){
            return Lists.newArrayList();
        }
        Multimap<String,MenuDto> menuDtoMultimap= ArrayListMultimap.create();
        List<MenuDto> rootList=Lists.newArrayList();
        for (MenuDto menuDto:menuDtoList){
            menuDtoMultimap.put(menuDto.getMenuLevel(),menuDto);
            if(LevelUtil.ROOT.equals(menuDto.getMenuLevel())){
                rootList.add(menuDto);
            }
        }
        rootList.sort(Comparator.comparingInt(Menu::getMenuOrder));
        //Recursive Traversal Tree
        transformMenuTree(menuDtoList,LevelUtil.ROOT,menuDtoMultimap);
        return rootList;
    }

    /**
     * transformMenuTree
     * @param menuDtoList
     * @param level
     * @param menuDtoMultimap
     */
    private void transformMenuTree(List<MenuDto> menuDtoList, String level, Multimap<String, MenuDto> menuDtoMultimap){
        for (MenuDto menuDto : menuDtoList) {
            String nextLevel = LevelUtil.calculateLevel(level, menuDto.getMenuOrder());
            List<MenuDto> tempMenDtoList = (List<MenuDto>) menuDtoMultimap.get(nextLevel);
            if (CollectionUtils.isEmpty(tempMenDtoList)) {
                //sort
                tempMenDtoList.sort(menuDtoComparator);
                //next menu
                menuDto.setMenuDtoList(tempMenDtoList);
                //deal with next level
                transformMenuTree(tempMenDtoList, nextLevel, menuDtoMultimap);
            }
        }
    }

    private Comparator<DepartmentDto> departmentDtoComparator= Comparator.comparingInt(Department::getDepartmentOrder);

    private Comparator<MenuDto> menuDtoComparator= Comparator.comparingInt(MenuDto::getMenuOrder);

    private Comparator<PermissionDto> permissionDtoComparator= Comparator.comparingInt(PermissionDto::getPermissionOrder);
}
